home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / Unix / Irix / audio_irix.cpp next >
Encoding:
C/C++ Source or Header  |  2001-02-02  |  10.4 KB  |  414 lines

  1. /*
  2.  *  audio_irix.cpp - Audio support, SGI Irix implementation
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include "sysdeps.h"
  22.  
  23. #include <sys/ioctl.h>
  24. #include <unistd.h>
  25. #include <errno.h>
  26. #include <pthread.h>
  27. #include <semaphore.h>
  28.  
  29. #include <dmedia/audio.h>
  30. #include <dmedia/dmedia.h>
  31.  
  32. #include "cpu_emulation.h"
  33. #include "main.h"
  34. #include "prefs.h"
  35. #include "user_strings.h"
  36. #include "audio.h"
  37. #include "audio_defs.h"
  38.  
  39. #define DEBUG 0
  40. #include "debug.h"
  41.  
  42.  
  43. // Supported sample rates, sizes and channels (defaults)
  44. int audio_num_sample_rates = 1;
  45. uint32 audio_sample_rates[] = {44100 << 16};
  46. int audio_num_sample_sizes = 1;
  47. uint16 audio_sample_sizes[] = {16};
  48. int audio_num_channel_counts = 1;
  49. uint16 audio_channel_counts[] = {2};
  50.  
  51. // Global variables
  52. static int audio_fd = -1;                            // fd from audio library
  53. static sem_t audio_irq_done_sem;                    // Signal from interrupt to streaming thread: data block read
  54. static bool sem_inited = false;                        // Flag: audio_irq_done_sem initialized
  55. static int sound_buffer_size;                        // Size of sound buffer in bytes
  56. static int sound_buffer_fill_point;                    // Fill buffer when this many frames are empty
  57. static uint8 silence_byte = 0;                        // Byte value to use to fill sound buffers with silence
  58. static pthread_t stream_thread;                        // Audio streaming thread
  59. static pthread_attr_t stream_thread_attr;            // Streaming thread attributes
  60. static bool stream_thread_active = false;            // Flag: streaming thread installed
  61. static volatile bool stream_thread_cancel = false;    // Flag: cancel streaming thread
  62.  
  63. // IRIX libaudio control structures
  64. static ALconfig config;
  65. static ALport   port;
  66.  
  67.  
  68. // Prototypes
  69. static void *stream_func(void *arg);
  70.  
  71.  
  72. /*
  73.  *  Initialization
  74.  */
  75.  
  76. // Set AudioStatus to reflect current audio stream format
  77. static void set_audio_status_format(void)
  78. {
  79.     AudioStatus.sample_rate = audio_sample_rates[0];
  80.     AudioStatus.sample_size = audio_sample_sizes[0];
  81.     AudioStatus.channels = audio_channel_counts[0];
  82. }
  83.  
  84. // Init libaudio, returns false on error
  85. bool audio_init_al(void)
  86. {
  87.     ALpv     pv[2];
  88.  
  89.     printf("Using libaudio audio output\n");
  90.  
  91.     // Try to open the audio library
  92.  
  93.     config = alNewConfig();
  94.     alSetSampFmt(config, AL_SAMPFMT_TWOSCOMP);
  95.     alSetWidth(config, AL_SAMPLE_16);
  96.     alSetChannels(config, 2);    // stereo
  97.     alSetDevice(config, AL_DEFAULT_OUTPUT); // Allow selecting via prefs?
  98.     
  99.     port = alOpenPort("BasiliskII", "w", config);
  100.     if (port == NULL) {
  101.         fprintf(stderr, "ERROR: Cannot open audio port: %s\n", 
  102.                 alGetErrorString(oserror()));
  103.         return false;
  104.     }
  105.  
  106.     // Set the sample rate
  107.  
  108.     pv[0].param = AL_RATE;
  109.     pv[0].value.ll = alDoubleToFixed(audio_sample_rates[0] >> 16);
  110.     pv[1].param = AL_MASTER_CLOCK;
  111.     pv[1].value.i = AL_CRYSTAL_MCLK_TYPE;
  112.     if (alSetParams(AL_DEFAULT_OUTPUT, pv, 2) < 0) {
  113.         fprintf(stderr, "ERROR: libaudio setparams failed: %s\n",
  114.                 alGetErrorString(oserror()));
  115.         alClosePort(port);
  116.         return false;
  117.     }
  118.  
  119.     // TODO:  list all supported sample formats?
  120.  
  121.     // Set AudioStatus again because we now know more about the sound
  122.     // system's capabilities
  123.     set_audio_status_format();
  124.  
  125.     // Compute sound buffer size and libaudio refill point
  126.  
  127.     config = alGetConfig(port);
  128.     audio_frames_per_block = alGetQueueSize(config);
  129.     if (audio_frames_per_block < 0) {
  130.         fprintf(stderr, "ERROR: couldn't get queue size: %s\n",
  131.                 alGetErrorString(oserror()));
  132.         alClosePort(port);
  133.         return false;
  134.     }
  135.     D(bug("alGetQueueSize %d\n", audio_frames_per_block));
  136.  
  137.     alZeroFrames(port, audio_frames_per_block);    // so we don't underflow
  138.  
  139.     // Put a limit on the Mac sound buffer size, to decrease delay
  140.     if (audio_frames_per_block > 2048)
  141.         audio_frames_per_block = 2048;
  142.     // Try to keep the buffer pretty full.  5000 samples of slack works well.
  143.     sound_buffer_fill_point = alGetQueueSize(config) - 5000;
  144.     if (sound_buffer_fill_point < 0)
  145.         sound_buffer_fill_point = alGetQueueSize(config) / 3;
  146.     D(bug("fill point %d\n", sound_buffer_fill_point));
  147.  
  148.     sound_buffer_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
  149.  
  150.     // Get a file descriptor we can select() on
  151.  
  152.     audio_fd = alGetFD(port);
  153.     if (audio_fd < 0) {
  154.         fprintf(stderr, "ERROR: couldn't get libaudio file descriptor: %s\n",
  155.                 alGetErrorString(oserror()));
  156.         alClosePort(port);
  157.         return false;
  158.     }
  159.  
  160.     return true;
  161. }
  162.  
  163.  
  164. /*
  165.  *  Initialization
  166.  */
  167.  
  168. void AudioInit(void)
  169. {
  170.     // Init audio status (defaults) and feature flags
  171.     set_audio_status_format();
  172.     AudioStatus.mixer = 0;
  173.     AudioStatus.num_sources = 0;
  174.     audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
  175.  
  176.     // Sound disabled in prefs? Then do nothing
  177.     if (PrefsFindBool("nosound"))
  178.         return;
  179.  
  180.     // Try to open audio library
  181.     if (!audio_init_al())
  182.             return;
  183.  
  184.     // Init semaphore
  185.     if (sem_init(&audio_irq_done_sem, 0, 0) < 0)
  186.         return;
  187.     sem_inited = true;
  188.  
  189.     // Start streaming thread
  190.     pthread_attr_init(&stream_thread_attr);
  191. #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
  192.     if (geteuid() == 0) {
  193.         pthread_attr_setinheritsched(&stream_thread_attr, PTHREAD_EXPLICIT_SCHED);
  194.         pthread_attr_setschedpolicy(&stream_thread_attr, SCHED_FIFO);
  195.         struct sched_param fifo_param;
  196.         fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
  197.         pthread_attr_setschedparam(&stream_thread_attr, &fifo_param);
  198.     }
  199. #endif
  200.     stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0);
  201.  
  202.     // Everything OK
  203.     audio_open = true;
  204. }
  205.  
  206.  
  207. /*
  208.  *  Deinitialization
  209.  */
  210.  
  211. void AudioExit(void)
  212. {
  213.     // Stop stream and delete semaphore
  214.     if (stream_thread_active) {
  215.         stream_thread_cancel = true;
  216. #ifdef HAVE_PTHREAD_CANCEL
  217.         pthread_cancel(stream_thread);
  218. #endif
  219.         pthread_join(stream_thread, NULL);
  220.         stream_thread_active = false;
  221.     }
  222.     if (sem_inited)
  223.         sem_destroy(&audio_irq_done_sem);
  224.  
  225.     // Close audio library
  226.     alClosePort(port);
  227. }
  228.  
  229.  
  230. /*
  231.  *  First source added, start audio stream
  232.  */
  233.  
  234. void audio_enter_stream()
  235. {
  236.     // Streaming thread is always running to avoid clicking noises
  237. }
  238.  
  239.  
  240. /*
  241.  *  Last source removed, stop audio stream
  242.  */
  243.  
  244. void audio_exit_stream()
  245. {
  246.     // Streaming thread is always running to avoid clicking noises
  247. }
  248.  
  249.  
  250. /*
  251.  *  Streaming function
  252.  */
  253.  
  254. static void *stream_func(void *arg)
  255. {
  256.     int16 *last_buffer = new int16[sound_buffer_size / 2];
  257.     fd_set audio_fdset;
  258.     int    numfds, was_error;
  259.  
  260.     numfds = audio_fd + 1;
  261.     FD_ZERO(&audio_fdset);
  262.  
  263.     while (!stream_thread_cancel) {
  264.         if (AudioStatus.num_sources) {
  265.  
  266.             // Trigger audio interrupt to get new buffer
  267.             D(bug("stream: triggering irq\n"));
  268.             SetInterruptFlag(INTFLAG_AUDIO);
  269.             TriggerInterrupt();
  270.             D(bug("stream: waiting for ack\n"));
  271.             sem_wait(&audio_irq_done_sem);
  272.             D(bug("stream: ack received\n"));
  273.  
  274.             uint32 apple_stream_info;    // Mac address of SoundComponentData struct describing next buffer
  275.             // Get size of audio data
  276.             apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo);
  277.  
  278.             if (apple_stream_info) {
  279.                 int work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels;
  280.                 D(bug("stream: work_size %d\n", work_size));
  281.                 if (work_size > sound_buffer_size)
  282.                     work_size = sound_buffer_size;
  283.                 if (work_size == 0)
  284.                     goto silence;
  285.  
  286.                 // Send data to audio library
  287.                 if (work_size == sound_buffer_size)
  288.                     alWriteFrames(port, Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)), audio_frames_per_block);
  289.                 else {
  290.                     // Last buffer
  291.                     Mac2Host_memcpy(last_buffer, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
  292.                     memset((uint8 *)last_buffer + work_size, silence_byte, sound_buffer_size - work_size);
  293.                     alWriteFrames(port, last_buffer, audio_frames_per_block);
  294.                 }
  295.                 D(bug("stream: data written\n"));
  296.             } else
  297.                 goto silence;
  298.  
  299.         } else {
  300.  
  301.             // Audio not active, play silence
  302.         silence:    // D(bug("stream: silence\n"));
  303.             alZeroFrames(port, audio_frames_per_block);
  304.         }
  305.  
  306.         // Wait for fill point to be reached (may be immediate)
  307.  
  308.         if (alSetFillPoint(port, sound_buffer_fill_point) < 0) {
  309.             fprintf(stderr, "ERROR: alSetFillPoint failed: %s\n",
  310.                     alGetErrorString(oserror()));
  311.             // Should stop the audio here....
  312.         }
  313.  
  314.         do {
  315.             errno = 0;
  316.             FD_SET(audio_fd, &audio_fdset);
  317.             was_error = select(numfds, NULL, &audio_fdset, NULL, NULL);
  318.         } while(was_error < 0 && (errno == EINTR));
  319.         if (was_error < 0) {
  320.             fprintf(stderr, "ERROR: select returned %d, errno %d\n",
  321.                     was_error, errno);
  322.             // Should stop audio here....
  323.         }
  324.     }
  325.     delete[] last_buffer;
  326.     return NULL;
  327. }
  328.  
  329.  
  330. /*
  331.  *  MacOS audio interrupt, read next data block
  332.  */
  333.  
  334. void AudioInterrupt(void)
  335. {
  336.     D(bug("AudioInterrupt\n"));
  337.  
  338.     // Get data from apple mixer
  339.     if (AudioStatus.mixer) {
  340.         M68kRegisters r;
  341.         r.a[0] = audio_data + adatStreamInfo;
  342.         r.a[1] = AudioStatus.mixer;
  343.         Execute68k(audio_data + adatGetSourceData, &r);
  344.         D(bug(" GetSourceData() returns %08lx\n", r.d[0]));
  345.     } else
  346.         WriteMacInt32(audio_data + adatStreamInfo, 0);
  347.  
  348.     // Signal stream function
  349.     sem_post(&audio_irq_done_sem);
  350.     D(bug("AudioInterrupt done\n"));
  351. }
  352.  
  353.  
  354. /*
  355.  *  Set sampling parameters
  356.  *  "index" is an index into the audio_sample_rates[] etc. arrays
  357.  *  It is guaranteed that AudioStatus.num_sources == 0
  358.  */
  359.  
  360. void audio_set_sample_rate(int index)
  361. {
  362. }
  363.  
  364. void audio_set_sample_size(int index)
  365. {
  366. }
  367.  
  368. void audio_set_channels(int index)
  369. {
  370. }
  371.  
  372.  
  373. /*
  374.  *  Get/set volume controls (volume values received/returned have the left channel
  375.  *  volume in the upper 16 bits and the right channel volume in the lower 16 bits;
  376.  *  both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume"))
  377.  */
  378.  
  379. bool audio_get_main_mute(void)
  380. {
  381.     return false;
  382. }
  383.  
  384. uint32 audio_get_main_volume(void)
  385. {
  386.     return 0x01000100;
  387. }
  388.  
  389. bool audio_get_speaker_mute(void)
  390. {
  391.     return false;
  392. }
  393.  
  394. uint32 audio_get_speaker_volume(void)
  395. {
  396.     return 0x01000100;
  397. }
  398.  
  399. void audio_set_main_mute(bool mute)
  400. {
  401. }
  402.  
  403. void audio_set_main_volume(uint32 vol)
  404. {
  405. }
  406.  
  407. void audio_set_speaker_mute(bool mute)
  408. {
  409. }
  410.  
  411. void audio_set_speaker_volume(uint32 vol)
  412. {
  413. }
  414.